const messages = require('./messages')
const {
  QUERY_LATEST,
  QUERY_ALL,
  RESPONSE_BLOCKCHAIN
} = require('./message-type');
const wrtc = require('electron-webrtc');
const Exchange = require('peer-exchange');
const p2p = new Exchange('dguan', { wrtc: wrtc });
const net = require('net');

export default class PeerToPeer {
  constructor(blockchain) {
    this.peers = [];
    this.blockchain=blockchain;
    
  }
  

  startServer (port) {
    const server = net.createServer(socket => p2p.accept(socket, (err, connection) => {
      if (err) {
        console.log(`❗  ${err}`);
      } else {
        console.log('👥  节点已连接到服务器!'+connection)

        this.initConnection.call(this, connection)
      }
    })).listen(port);
    console.log(`📡  监听端口 ${server.address().address}:${server.address().port}... `);
  }

  connectToPeer(host, port) {
    const socket = net.connect(port, host, () => p2p.connect(socket, (err, connection) => {
      if (err) {
        console.log(`❗  ${err}`);
      } else {
        console.log('👥  已成功连接到新的节点!');
        this.initConnection.call(this, connection);
      }
    }));
  }

  discoverPeers() {
    p2p.getNewPeer((err) => {
      if (err) {
        console.log(`❗  ${err}`);
      } else {
        console.log('👀  发现新的节点.') //todo
      }
    })
  }

  initConnection(connection) {
    this.peers.push(connection);
    this.initMessageHandler(connection);
    this.initErrorHandler(connection);
    this.write(connection, messages.getQueryChainLengthMsg());
  }

  initMessageHandler(connection) {
    connection.on('data', data => {
      const message = JSON.parse(data.toString('utf8'));
      this.handleMessage(connection, message);
    })
  }

  handleMessage(peer, message) {
    switch (message.type) {
      case QUERY_LATEST:
        console.log(`⬇  节点 请求最新块.`);
        this.write(peer, messages.getResponseLatestMsg(this.blockchain))
        break
      case QUERY_ALL:
        console.log("⬇ 节点 请求的区块链.");
        this.write(peer, messages.getResponseChainMsg(this.blockchain))
        break
      case RESPONSE_BLOCKCHAIN:
        this.handleBlockchainResponse(message)
        break
      default:
        console.log(`❓  收到未知消息类型 ${message.type}`)
    }
  }

  initErrorHandler(connection) {
    connection.on('error', error => console.log(`❗  ${error}`));
  }

  broadcastLatest () {
    this.broadcast(messages.getResponseLatestMsg(this.blockchain))
  }

  broadcast(message) {
    this.peers.forEach(peer => this.write(peer, message))
  }

  write(peer, message) {
    peer.write(JSON.stringify(message));
  }

  closeConnection() {

  }

  handleBlockchainResponse(message) {
    const receivedBlocks = JSON.parse(message.data).sort((b1, b2) => (b1.index - b2.index));
    const latestBlockReceived = receivedBlocks[receivedBlocks.length - 1];
    const latestBlockHeld = this.blockchain.latestBlock;

    const blockOrChain = receivedBlocks.length === 1 ? 'single block' : 'blockchain';
    console.log(`⬇  节点发送过来 ${blockOrChain}.`);

    if (latestBlockReceived.index <= latestBlockHeld.index) {
      console.log(`💤  收到的最新区块不长于当前区块链。什么也不做`)
      return null;
    }

    console.log(`🐢  区块链可能在后面。收到的最新数据块是 #${latestBlockReceived.index}. 当前最新块为 #${latestBlockHeld.index}.`);
    if (latestBlockHeld.hash === latestBlockReceived.previousHash) {
      console.log(`👍  收到的上一个哈希值等于当前哈希值。将接收到的块附加到区块链.`)
        this.blockchain.addBlockFromPeer(latestBlockReceived)
      this.broadcast(messages.getResponseLatestMsg(this.blockchain))
    } else if (receivedBlocks.length === 1) {
      console.log(`🤔  收到的上一个哈希与当前哈希不同。从对等方获取整个区块链.`)
      this.broadcast(messages.getQueryAllMsg())
    } else {
      console.log(`⛓  节点的区块链比当前区块链长.`)
        this.blockchain.replaceChain(receivedBlocks)
      this.broadcast(messages.getResponseLatestMsg(this.blockchain))
    }
  }
}
